package com.mangofactory.aop.interceptors
{
	import com.mangofactory.aop.aspects.Aspect;
	import com.mangofactory.aop.joinpoints.AspectInvokingJoinPoint;
	import com.mangofactory.aop.joinpoints.MethodInvokingJoinPoint;
	import com.mangofactory.aop.joinpoints.ProceedingJoinPoint;
	
	import org.as3commons.bytecode.interception.IInterceptor;
	import org.as3commons.bytecode.interception.IMethodInvocation;
	
	public class AspectInvokingInterceptor implements IInterceptor
	{
		private var _aspects:Vector.<Aspect>
		public function AspectInvokingInterceptor(aspects:Vector.<Aspect>=null)
		{
			this._aspects = aspects || new Vector.<Aspect>();
		}
		
		public function intercept(invocation:IMethodInvocation):void
		{
			// TODO : Consider sorting
			var joinPoint:ProceedingJoinPoint = new MethodInvokingJoinPoint(invocation);
			var remainingAspects:Vector.<Aspect> = aspects.concat();
			while (remainingAspects.length > 0)
			{
				var nextAspect:Aspect = remainingAspects.pop();
				joinPoint = new AspectInvokingJoinPoint(nextAspect,joinPoint);
			}
			joinPoint.proceed();
			// prevent the IMethodInvocation from continuing, as we've already invoked it
			invocation.proceed = false;
		}

		public function addAspect(aspect:Aspect):void
		{
			_aspects.push(aspect);
		}
		public function get aspects():Vector.<Aspect>
		{
			return _aspects;
		}

		public function addAspects(aspects:Vector.<Aspect>):void
		{
			for each (var aspect:Aspect in aspects)
			{
				addAspect(aspect);
			}
		}
	}
}